/*
#include <serial.h>
 * Copyright (c) 2006-2021, RT-Halo Team
 *
 * SPDX-License-Identifier: GPLv3
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-11-19     Eywen       the first version
 */

#include "serial.h"
#include <rtthread.h>
#include <stdarg.h>
#include <string.h>

#include "gcode/gcode.h"

#define SERIAL_UART_NAME       "uart6"      /* 串口设备名称， RX: PC7(39) TX:PC6(38) */
static rt_device_t serial;
/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    /* 串口接收到数据后产生中断，调用此回调函数，然后发送接收信号量 */
    rt_sem_release(&rx_sem);

    return RT_EOK;
}

/* 串口接收处理线程，可以域解析每条gcode */
static void serial_thread_entry(void *parameter)
{
    extern gcode_handle_t gcode_handle;
    gcode_t gcode;
    char str[GCODE_STR_MAX_LEN];
    char ch;
    int cnt = 0;
    while (1){
        ch = 0;
        cnt = 0;

        while(ch != '\n'){
            /* 从串口读取一个字节的数据，没有读取到则等待接收信号量 */
//            while(rt_device_read(serial, -1, &ch, 1) != 1){
//                rt_thread_mdelay(10);
//            }
            while (rt_device_read(serial, -1, &ch, 1) != 1){
                /* 阻塞等待接收信号量，等到信号量后再次读取数据 */
                //rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
                /* 超时500ms, 则认为接收完整一串gcode失败 */
                if(RT_EOK != rt_sem_take(&rx_sem, 500) && (cnt != 0)){
                    cnt = 0;
                    /* 删去完剩下的所有字符 */
                    while(rt_device_read(serial, -1, &ch, 1) == 1){
                        /* 等待一会儿接收下一个字符 */
                        rt_thread_mdelay(10);
                    }
                    /* 回复接收失败 */
                    serial_echo_string(GCODE_REPY_ERR_STR);
                    debug_info("recv timeout");
                    continue;
                }
            }
            str[cnt++] = ch;
            //debug_info("recv: %c", ch);
        }
        str[cnt] = '\0';
        debug_info("recv: %s", str);

        /* 队列满了 */
        if(gcode_handle.ops->task_full(&gcode_handle) == true){
            serial_echo_string(GCODE_BUSY_STR);
            rt_thread_mdelay(1);
            continue;
        }

        /* 解析正确，送入gcode处理任务 */
        if(true == parse_gcode_str(&gcode, str)){
            /* 回复 */
            serial_echo_string(GCODE_REPY_OK_STR);
            gcode_handle.ops->add_gcode(&gcode_handle, &gcode);
        }
        else{
            /* gcode错误，返回err */
            serial_echo_string(GCODE_REPY_ERR_STR);
        }
    }
}

bool serial_thread_init(const char *serial_name)
{
    rt_err_t ret = RT_EOK;
    char *uart_name;
    if(serial_name == NULL){
        uart_name = (char *)SERIAL_UART_NAME;
    }
    else{
        uart_name = (char *)serial_name;
    }

    /* 查找串口设备 */
    serial = rt_device_find(uart_name);
    if (!serial){
        debug_warn("find %s failed!\n", uart_name);
        return RT_ERROR;
    }
    else{
        debug_info("find ok");
    }

    /* 初始化信号量 */
    rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
    /* 以读写及中断接收方式打开串口设备 */
    rt_device_open(serial, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
    rt_device_set_rx_indicate(serial, uart_input);

    /* 创建 serial 线程 */
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 2048, 10, 10);
    /* 创建成功则启动线程 */
    if (thread != RT_NULL){
        rt_thread_startup(thread);
    }
    else{
        ret = RT_ERROR;
    }

    return ret;
}


bool serial_echo_string(char *str)
{
    debug_info("%s", str);
    rt_enter_critical();
    rt_device_write(serial, 0, str, strlen(str));
    rt_exit_critical();
    return true;
}

bool serial_echo(const char *format, ...)
{
    va_list args;
    int n;
    static char debug_buff[254];
    va_start(args, format);
    n = rt_vsnprintf(debug_buff, 254, format, args);
    va_end(args);
    rt_device_write(serial, 0, debug_buff, n);
    return 0;
}
